/**
 * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 */

package com.iwindplus.boot.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import com.fasterxml.jackson.core.type.TypeReference;
import com.iwindplus.boot.domain.constant.CommonConstant.SymbolConstant;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;

/**
 * API签名工具类.
 *
 * @author zengdegui
 * @since 2021/1/11
 */
@Slf4j
public class ApiSignUtil {

    /**
     * 生成签名.
     * </p>
     * 规则：第一步，将参数按照字典序排序，拼接成字符串，第二步，将上一步的HmacSHA256进行编码，第三步，将上一步的进行MD5编码）
     *
     * @param params    请求参数
     * @param secretKey 密钥
     * @return String
     */
    public static String generateSign(Map<String, Object> params, String secretKey) {
        // 将参数按照字典序排序，拼接成字符串，例如 "key1=value1&key2=value2"
        String sortedParams = params.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .map(entry -> entry.getKey() + SymbolConstant.EQUAL + entry.getValue())
            .reduce((s1, s2) -> s1 + SymbolConstant.LOGICAL_AND + s2).orElse("");

        // 计算摘要
        HMac hmac = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, secretKey);
        return SecureUtil.md5(hmac.digestHex(sortedParams));
    }

    /**
     * 将 JSON 字符串转换为 Map 并生成签名.
     *
     * @param json      JSON 格式请求参数
     * @param secretKey 密钥
     * @return String
     */
    public static String generateSignFromJson(String json, String secretKey) {
        Map<String, Object> params = JacksonUtil.parseObject(json, new TypeReference<>() {
        });
        return generateSign(params, secretKey);
    }

    /**
     * 验证签名.
     *
     * @param params    请求参数
     * @param secretKey 密钥
     * @param signature 签名
     * @return boolean
     */
    public static boolean verifySign(Map<String, Object> params, String secretKey, String signature) {
        String calculatedSign = generateSign(params, secretKey);
        return StrUtil.equals(signature, calculatedSign);
    }

    /**
     * 将 JSON 字符串转换为 Map 并验证签名.
     *
     * @param json      JSON 格式请求参数
     * @param secretKey 密钥
     * @param signature 签名
     * @return boolean
     */
    public static boolean verifySignFromJson(String json, String secretKey, String signature) {
        Map<String, Object> params = JacksonUtil.parseObject(json, new TypeReference<>() {
        });
        return verifySign(params, secretKey, signature);
    }
}